package com.weai.service.impl;

import com.weai.dto.TaskDTO;
import com.weai.dto.TaskQueryDTO;
import com.weai.entity.Task;
import com.weai.exception.ResourceNotFoundException;
import com.weai.repository.TaskRepository;
import com.weai.service.TaskService;
import jakarta.persistence.criteria.Predicate;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 任务服务实现类
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class TaskServiceImpl implements TaskService {

    private final TaskRepository taskRepository;
    
    /**
     * 创建任务
     *
     * @param taskDTO 任务信息
     * @return 创建后的任务信息
     */
    @Override
    @Transactional
    public TaskDTO createTask(TaskDTO taskDTO) {
        log.info("创建任务: {}", taskDTO.getTitle());
        
        // 设置当前周的周一和周日日期
        LocalDate now = LocalDate.now();
        LocalDate startOfWeek = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        LocalDate endOfWeek = now.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));

        // 生成标题索引：当前时间(年月日时分)+创建者
        String titleIndex = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmm")) + "_" + taskDTO.getCreater();

        // 创建任务实体
        Task task = Task.builder()
                .title(taskDTO.getTitle())
                .titleIndex(titleIndex)
                .status(taskDTO.getStatus() != null ? taskDTO.getStatus() : "todo")
                .periodStartDate(startOfWeek)
                .periodEndDate(endOfWeek)
                .type(taskDTO.getType())
                .subType(taskDTO.getSubType())
                .level(taskDTO.getLevel())
                .process(taskDTO.getProcess())
                .thisWeekPlan(taskDTO.getThisWeekPlan())
                .nextWeekPlan(taskDTO.getNextWeekPlan())
                .problems(taskDTO.getProblems())
                .parentId(taskDTO.getParentId())
                .creater(taskDTO.getCreater())
                .receiver(taskDTO.getReceiver())
                .createdTime(LocalDateTime.now())
                .build();

        Task savedTask = taskRepository.save(task);
        log.info("任务创建成功, ID: {}", savedTask.getId());
        
        return convertToDTO(savedTask);
    }
    
    /**
     * 更新任务
     *
     * @param id 任务ID
     * @param taskDTO 任务信息
     * @return 更新后的任务信息
     */
    @Override
    @Transactional
    public TaskDTO updateTask(Integer id, TaskDTO taskDTO) {
        log.info("更新任务, ID: {}", id);
        
        Task task = taskRepository.findById(id)
                .orElseThrow(() -> {
                    log.error("任务不存在, ID: {}", id);
                    return new ResourceNotFoundException("任务不存在: " + id);
                });
        // 更新任务信息
        task.setTitle(taskDTO.getTitle());
        task.setStatus(taskDTO.getStatus());
        task.setType(taskDTO.getType());
        task.setSubType(taskDTO.getSubType());
        task.setLevel(taskDTO.getLevel());
        task.setProcess(taskDTO.getProcess());
        task.setThisWeekPlan(taskDTO.getThisWeekPlan());
        task.setNextWeekPlan(taskDTO.getNextWeekPlan());
        task.setProblems(taskDTO.getProblems());
        
        // 特殊处理parentId：如果DTO中的parentId为null但原任务已有parentId值，则保留原值
        if (taskDTO.getParentId() == null && task.getParentId() != null) {
            log.info("保留原有父任务ID: {}, 任务ID: {}", task.getParentId(), id);
        } else {
            task.setParentId(taskDTO.getParentId());
        }
        
        task.setReceiver(taskDTO.getReceiver());
        task.setExpectedDate(taskDTO.getExpectedDate());
        task.setFinishedDate(taskDTO.getFinishedDate());
        
        // 更新修改人
        task.setUpdater(taskDTO.getUpdater());
        task.setUpdateTime(LocalDateTime.now());
        
        Task updatedTask = taskRepository.save(task);
        log.info("任务更新成功, ID: {}", updatedTask.getId());
        
        return convertToDTO(updatedTask);
    }
    
    /**
     * 根据ID查询任务
     *
     * @param id 任务ID
     * @return 任务信息
     */
    @Override
    public TaskDTO findById(Integer id) {
        log.info("根据ID查询任务: {}", id);
        
        Task task = taskRepository.findById(id)
                .orElseThrow(() -> {
                    log.error("任务不存在, ID: {}", id);
                    return new ResourceNotFoundException("任务不存在: " + id);
                });
        
        return convertToDTO(task);
    }
    
    /**
     * 根据ID删除任务
     *
     * @param id 任务ID
     */
    @Override
    @Transactional
    public void deleteById(Integer id) {
        log.info("删除任务, ID: {}", id);
        
        if (!taskRepository.existsById(id)) {
            log.error("任务不存在, ID: {}", id);
            throw new ResourceNotFoundException("任务不存在: " + id);
        }
        
        taskRepository.deleteById(id);
        log.info("任务删除成功, ID: {}", id);
    }
    
    /**
     * 查询所有任务并按状态分组
     *
     * @param queryDTO 查询条件
     * @return 按状态分组的任务列表
     */
    @Override
    public Map<String, List<TaskDTO>> findAllGroupByStatus(TaskQueryDTO queryDTO) {
        log.info("查询任务列表, 条件: {}", queryDTO);
        
        // 构建动态查询条件
        Specification<Task> specification = buildSpecification(queryDTO);
        
        // 查询任务列表
        List<Task> tasks = taskRepository.findAll(specification);
        log.info("查询到 {} 条任务记录", tasks.size());
        
        // 转换为DTO并按状态分组
        return tasks.stream()
                .map(this::convertToDTO)
                .collect(Collectors.groupingBy(
                        TaskDTO::getStatus,
                        LinkedHashMap::new,
                        Collectors.toList()
                ));
    }
    
    /**
     * 查询当前用户的任务
     *
     * @param username 用户名
     * @return 按状态分组的任务列表
     */
    @Override
    public Map<String, List<TaskDTO>> findMyTasks(String username) {
        log.info("查询用户 {} 的任务", username);
        
        // 使用模糊查询，查找接收人包含当前用户的任务
        // 模式中的%表示任何字符序列，这样可以匹配receiver字段中包含username的任务
        String receiverPattern = "%" + username + "%";
        List<Task> tasks = taskRepository.findByCreaterOrReceiverContaining(username, receiverPattern);
        log.info("查询到用户 {} 的 {} 条任务记录", username, tasks.size());
        
        // 转换为DTO并按状态分组
        return tasks.stream()
                .map(this::convertToDTO)
                .collect(Collectors.groupingBy(
                        TaskDTO::getStatus,
                        LinkedHashMap::new,
                        Collectors.toList()
                ));
    }
    
    /**
     * 更新任务状态
     *
     * @param id 任务ID
     * @param status 任务状态
     * @return 更新后的任务信息
     */
    @Override
    @Transactional
    public TaskDTO updateTaskStatus(Integer id, String status) {
        log.info("更新任务状态, ID: {}, 状态: {}", id, status);
        
        Task task = taskRepository.findById(id)
                .orElseThrow(() -> {
                    log.error("任务不存在, ID: {}", id);
                    return new ResourceNotFoundException("任务不存在: " + id);
                });
        
        // 记录任务原有的parentId，确保不会丢失
        String originalParentId = task.getParentId();
        
        task.setStatus(status);
        
        // 如果任务状态变为"已完成"，自动设置完成时间
        if ("done".equals(status) && task.getFinishedDate() == null) {
            task.setFinishedDate(LocalDate.now());
            log.info("任务状态变为已完成，自动设置完成时间: {}", task.getFinishedDate());
        }
        
        // 确保parentId不会丢失
        if (originalParentId != null) {
            task.setParentId(originalParentId);
            log.info("保留任务更新状态时的父任务ID: {}, 任务ID: {}", originalParentId, id);
        }
        
        // 更新修改时间
        task.setUpdateTime(LocalDateTime.now());
        
        Task updatedTask = taskRepository.save(task);
        log.info("任务状态更新成功, ID: {}, 新状态: {}", id, status);
        
        return convertToDTO(updatedTask);
    }
    
    /**
     * 根据titleIndex查询任务
     *
     * @param titleIndex 任务唯一标识
     * @return 任务信息
     */
    @Override
    public TaskDTO findByTitleIndex(String titleIndex) {
        log.info("根据titleIndex查询任务: {}", titleIndex);
        
        Task task = taskRepository.findByTitleIndex(titleIndex);
        if (task == null) {
            log.warn("未找到titleIndex为{}的任务", titleIndex);
            return null;
        }
        
        return convertToDTO(task);
    }
    
    /**
     * 根据parentId查询子任务列表
     *
     * @param parentId 父任务ID
     * @return 子任务列表
     */
    @Override
    public List<TaskDTO> findChildTasks(String parentId) {
        log.info("查询parentId为{}的子任务", parentId);
        
        List<Task> childTasks = taskRepository.findByParentId(parentId);
        log.info("找到{}个子任务", childTasks.size());
        
        return childTasks.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }


    /**
     * 构建动态查询条件
     *
     * @param queryDTO 查询条件
     * @return 查询规范
     */
    private Specification<Task> buildSpecification(TaskQueryDTO queryDTO) {
        return (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            
            // 按标题模糊查询
            if (StringUtils.hasText(queryDTO.getTitle())) {
                predicates.add(cb.like(root.get("title"), "%" + queryDTO.getTitle() + "%"));
            }
            
            // 按创建者查询
            if (StringUtils.hasText(queryDTO.getCreater())) {
                predicates.add(cb.equal(root.get("creater"), queryDTO.getCreater()));
            }
            
            // 按处理人查询
            if (StringUtils.hasText(queryDTO.getReceiver())) {
                predicates.add(cb.equal(root.get("receiver"), queryDTO.getReceiver()));
            }
            
            // 按需求类型查询
            if (StringUtils.hasText(queryDTO.getType())) {
                predicates.add(cb.equal(root.get("type"), queryDTO.getType()));
            }
            
            // 按子类型查询（多选）
            if (queryDTO.getSubTypes() != null && !queryDTO.getSubTypes().isEmpty()) {
                predicates.add(root.get("subType").in(queryDTO.getSubTypes()));
            }
            
            // 查询我的任务（创建者是当前用户或接收人包含当前用户）
            if (Boolean.TRUE.equals(queryDTO.getIsMyTask()) && StringUtils.hasText(queryDTO.getCurrentUser())) {
                Predicate createrPredicate = cb.equal(root.get("creater"), queryDTO.getCurrentUser());
                // 使用like查询，匹配receiver字段中包含当前用户的情况
                Predicate receiverPredicate = cb.like(root.get("receiver"), "%" + queryDTO.getCurrentUser() + "%");
                predicates.add(cb.or(createrPredicate, receiverPredicate));
            }

            // 添加本周一到周日的日期范围查询条件
            LocalDate now = LocalDate.now();
            LocalDate startOfWeek = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
            LocalDate endOfWeek = now.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
            predicates.add(cb.equal(root.get("periodStartDate"), startOfWeek));
            predicates.add(cb.equal(root.get("periodEndDate"), endOfWeek));

            return cb.and(predicates.toArray(new Predicate[0]));
        };
    }
    
    /**
     * 将实体转换为DTO
     *
     * @param task 任务实体
     * @return 任务DTO
     */
    private TaskDTO convertToDTO(Task task) {
        return TaskDTO.builder()
                .id(task.getId())
                .title(task.getTitle())
                .titleIndex(task.getTitleIndex())
                .status(task.getStatus())
                .periodStartDate(task.getPeriodStartDate())
                .periodEndDate(task.getPeriodEndDate())
                .type(task.getType())
                .subType(task.getSubType())
                .level(task.getLevel())
                .process(task.getProcess())
                .thisWeekPlan(task.getThisWeekPlan())
                .nextWeekPlan(task.getNextWeekPlan())
                .problems(task.getProblems())
                .parentId(task.getParentId())
                .creater(task.getCreater())
                .receiver(task.getReceiver())
                .updater(task.getUpdater())
                .expectedDate(task.getExpectedDate())
                .finishedDate(task.getFinishedDate())
                .createdTime(task.getCreatedTime())
                .updateTime(task.getUpdateTime())
                .build();
    }
} 